package main

import "fmt"

// 声明空结构体测试结构体逃逸情况
type Data struct {
}

func dummyData() *Data {

	// 实例化 c 为 Data 类型
	var c Data

	// 返回函数局部变量地址
	return &c
}

func main() {

	fmt.Println(dummyData())
}

// 代码说明如下：
// ● 第6行，声明一个空的结构体做结构体逃逸分析。
// ● 第9行，将dummy()函数的返回值修改为*Data指针类型。
// ● 第12行，将c变量声明为Data类型，此时c的结构体为值类型。
// ● 第15行，取函数局部变量c的地址并返回。Go语言的特性允许这样做。
// ● 第20行，打印dummy()函数的返回值。

// 执行逃逸分析：
// go run -gcflags "-m -l" address.go

// 输出内容如下：
// # command-line-arguments
// ./address.go:11:6: moved to heap: c
// ./address.go:17:13: ... argument does not escape
// &{}

// 注意第4行出现了新的提示：将c移到堆中。
// 这句话表示，Go编译器已经确认如果将c变量分配在栈上是无法保证程序最终结果的。
// 如果坚持这样做，dummy()的返回值将是Data结构的一个不可预知的内存地址。
// 这种情况一般是C/C++语言中容易犯错的地方：引用了一个函数局部变量的地址。

// Go语言最终选择将c的Data结构分配在堆上。然后由垃圾回收器去回收c的内存。
